<?php
/**
 * Created by PhpStorm.
 * User: yf
 * Date: 2018/5/28
 * Time: 下午6:33
 */
namespace EasySwoole\EasySwoole;

use App\WebSocket\WebSocketEvent;
use App\WebSocket\WebSocketParser;
use EasySwoole\EasySwoole\AbstractInterface\Event;
use EasySwoole\EasySwoole\Swoole\EventRegister;
use EasySwoole\Http\Request;
use EasySwoole\Http\Response;
use EasySwoole\Socket\Dispatcher;
use EasySwoole\RedisPool\Config as RedisConfig; // Resis池的CONFIG
use EasySwoole\Socket\Config as SocketConfig;
use swoole_server;
use swoole_http_request;
use swoole_http_response;
use swoole_websocket_frame;
use swoole_websocket_server;
use App\Utility\Pool\RedisPool;
use EasySwoole\Component\Pool\PoolManager;
use App\Utility\BaseEnum;
use EasySwoole\Component\Process\Config as ProceConfig;
use App\Utility\Pool\MySQLPool;
use EasySwoole\FastCache\Cache;
use EasySwoole\FastCache\SyncData;
use EasySwoole\FastCache\CacheProcessConfig;
use EasySwoole\Utility\File;
use App\Process\CommProcess;

class EasySwooleEvent implements Event
{

    /**
     * TODO 框架初始化事件
     * TO 在Swoole没有启动之前 会先执行这里的代码
     * TODO 注册使用REDIS 功能
     */
    public static function initialize()
    {
        @date_default_timezone_set('Asia/Shanghai'); // 设置时区

        /*
         * $configData = Config::getInstance()->getConf('REDIS'); //本项目配置的Config
         * $redisConfig = new RedisConfig($configData);
         * $redisPool = Redis::getInstance()->register('redis',$redisConfig);
         * $redisPool->setMaxObjectNum($configData['maxObjectNum']);
         * $redisPool->setMinObjectNum($configData['minObjectNum']);
         */
    }

    // TODO 进程管理
    private static function managerProcess()
    {
        $processConfig = new ProceConfig();
        $processConfig->setProcessName('commonProcess');
        $processConfig->setArg([
            "logger" => "common",
            'arg1' => BaseEnum::getNowTime(FALSE)
        ]);
        $LogProcess = (new CommProcess($processConfig))->getProcess();
        ServerManager::getInstance()->getSwooleServer()->addProcess($LogProcess);
    }

    
    
    /**
     * TODO 注册缓存服务
     */
    private static function doFastCacheAction(){
        //TODO 每隔5秒将数据存回文件
        Cache::getInstance()->setTickInterval(5 * 1000);//设置定时频率
        Cache::getInstance()->setOnTick(function(SyncData $syncObject , CacheProcessConfig  $cacheSetObj ){
            $cashData = [
                "data"=> $syncObject->getArray(),
                "queue"=>$syncObject->getQueueArray(),
                "ttl"=>$syncObject->getTtlKeys()
            ];
            //转存文件中
            $cachePath = EASYSWOOLE_TEMP_DIR . '/FastCacheData/' . $cacheSetObj->getProcessName();
            File::createFile($cachePath,serialize($cashData));
        });
        
        //TODO 启动时将存回的文件重新写入
        Cache::getInstance()->setOnStart(function (CacheProcessConfig $cacheSetObj) {
            $cachePath = EASYSWOOLE_TEMP_DIR . '/FastCacheData/' . $cacheSetObj->getProcessName();
            if(is_file($cachePath)){
                $cashstring = file_get_contents($cachePath); //缓存数据格式
                $data = !empty($cashstring) ? unserialize($cashstring) : FALSE;
                $syncData = new SyncData();
                if (!empty($data) && isset($data['data']) && isset($data['queue'])) {
                    $syncData->setArray($data['data']);
                    $syncData->setQueueArray($data['queue']);
                    $syncData->setTtlKeys(($data['ttl']));
                }return $syncData;
            }
        });
        
        
        //TODO 在守护进程时,php easyswoole stop 时会调用,落地数据
        Cache::getInstance()->setOnShutdown(function (SyncData $syncObject, CacheProcessConfig $cacheSetObj) {
            $cashData = [
                "data"=> $syncObject->getArray(),
                "queue"=>$syncObject->getQueueArray(),
                "ttl"=>$syncObject->getTtlKeys()
            ];
            $cachePath = EASYSWOOLE_TEMP_DIR . '/FastCacheData/' . $cacheSetObj->getProcessName();
            File::createFile($cachePath,serialize($cashData));
        });
        
        
       //TODO 全局注册缓存 FastCache
       Cache::getInstance()->setTempDir(EASYSWOOLE_TEMP_DIR)->attachToServer(ServerManager::getInstance()->getSwooleServer());
    }
    
    
    // TODO WEBSOCKET 控制器管理
    private static function managerWSAction(EventRegister $register)
    {
            $socketConfig = new SocketConfig();                 // 创建一个 Dispatcher 配置
            $socketConfig->setMaxPoolNum(1000);
            $socketConfig->setType(SocketConfig::WEB_SOCKET);   // 设置 Dispatcher 为 WebSocket 模式
            $socketConfig->setParser(new WebSocketParser());    // 设置解析器对象
            $dispatchObj = new Dispatcher($socketConfig);       // 创建 Dispatcher 对象 并注入 config 对象

            // TODO 给 server 注册相关事件 在 WebSocket 模式下 on message 事件必须注册 并且交给 Dispatcher 对象处理
            $register->set(EventRegister::onMessage, function (swoole_websocket_server $server, swoole_websocket_frame $frame) use ($dispatchObj) {
                $dispatchObj->dispatch($server, $frame->data, $frame);
            });
        
            /*
             * TODO -----------------事件绑定------------------- 
             * TO 注册相关的事件内容(自定义)
             * TO 注册数据库协程连接池(onWorkerStart)
             * TO 例如：事件onConnect,onOpen，onClose,onWorkerStart
             */
            $register->set($register::onConnect,    [ WebSocketEvent::class, 'onConnect' ]);
            $register->add($register::onOpen,       [ WebSocketEvent::class, 'onOpen' ]);
            $register->set($register::onClose,      [ WebSocketEvent::class, 'onClose']);
            $register->set($register::onWorkerStart,[ WebSocketEvent::class, 'onWorkerStart']);
            $register->set($register::onHandShake,  [ WebSocketEvent::class, 'onHandShake']);   // TODO 握手 , 关闭事件
     }
     
     
     /**
      * TODO 添加子服务
      */
     private static function addChildServer($child_port = 9503){
         if(!$child_port) $child_port = 9503;
         BaseEnum::Logger("添加子服务：端口{$child_port}, 创建服务对象 ","user-login");
         
         $cService = ServerManager::getInstance()->getSwooleServer()->addListener('0.0.0.0',$child_port,SWOOLE_SOCK_TCP);
         $cService->on('receive',function (swoole_server $server, int $fd, int $reactor_id, string $data){
             BaseEnum::Logger("子服务事件 ：receive fd={$fd},workerid={$reactor_id} 接收消息：" .json_encode($data),"user-login");
             var_dump($data);
         });
         
         $cService->on('message',function (swoole_server $server, $frame){
             BaseEnum::Logger("子服务事件 ：message fd={$fd},workerid={$reactor_id} 接收消息：" .json_encode($frame),"user-login");
             var_dump($data);
         });
     }

    /**
     * TODO 注册主服务
     *
     * @param EventRegister $register
     * @throws \Exception ||**************** websocket控制器 **********************||
     */
    public static function mainServerCreate(EventRegister $register)
    {
        //TODO ||--注册Redis连接池--||
        $ConfigRedis = Config::getInstance()->getConf('REDIS');                             //本项目配置的Config
        $rePobj = PoolManager::getInstance()->register(RedisPool::class);                   // 原先的REDIS池
        $rePobj->setMaxObjectNum($ConfigRedis['maxObjectNum']);
        $rePobj->setMinObjectNum($ConfigRedis['minObjectNum']);
        
        //TODO  ||--注册Mysql连接池--||
        //if (Config::getInstance()->getConf('MYSQL_POOL') === TRUE) {}
        $maxPoolNum = Config::getInstance()->getConf('MYSQL.POOL_MAX_NUM');                 //本项目配置的MYSQL
        PoolManager::getInstance()->register(MySQLPool::class, $maxPoolNum);                //DB池
        
        //TODO  ||--注册事件--||
        self::managerWSAction($register);

        
        //TODO  ||--注册缓存机制--||
        self::doFastCacheAction();
        
        
        //TODO ||---加子服务----||
        //self::addChildServer(9503);
        
        //TODO  ||--进程管理--||
        self::managerProcess();
        
        //TODO 增加日志写入之后的回调函数
        Logger::getInstance()->onLog()->set('mySelfLogFun',function ($msg,$logLevel,$category){
            $nowdate = date('Ym');
            $nowtime = date("H:i:s");
            $realPath = dirname(__FILE__).'/';
            $fullDir = $realPath .'Log/'.$nowdate ;
            if (!is_dir($fullDir)) @mkdir($fullDir);
            $logFile = $fullDir.'/print_' . date('md_H').'.log' ;
            //TODO 记录日志文件名称；按文件数据目录来处理
            if (!empty($nowtime) && substr($nowtime, -5) == '00:00') {
                @file_put_contents("Log/log.log", "[$nowtime] SWOOLE目录:[{$realPath}] Del Or New LogFile!\n"); 
            }
            if(!file_exists($logFile)){ @file_put_contents($logFile, "[$nowtime] SWOOLE目录:[{$realPath}] New LogFile!\n"); }
            //$message = (strlen($message) > 250) ? substr($message, 0,1030) : $message;
            @file_put_contents($logFile , "[{$category}-".date("H:i:s")."] {$msg}\n" , FILE_APPEND|LOCK_EX);
        });
    }

    public static function onRequest(Request $request, Response $response): bool
    {
        return true;
    }

    public static function afterRequest(Request $request, Response $response): void
    {
        
    }

    public static function onReceive(\swoole_server $server, int $fd, int $reactor_id, string $data): void
    {
        
    }
}
